%%% Copyright 2010 Google Inc.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
%%% You may obtain a copy of the License at
%%%
%%%     http://www.apache.org/licenses/LICENSE-2.0
%%%
%%% Unless required by applicable law or agreed to in writing, software
%%% distributed under the License is distributed on an "AS IS" BASIS,
%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%%% See the License for the specific language governing permissions and
%%% limitations under the License.

%%% @copyright 2010 Google Inc. All Rights Reserved.
%%% @author <jacoby@google.com> Jacoby Thwaites [http://sites/madcloud]
%%% @version {@version}
%%% @doc
%%% Event handler for TXM info, warning and error events.
%%%
%%% @headerfile "../include/txm.hrl"

-module(txm_log).

-behaviour(gen_event).

-include("txm.hrl").

%%% ---------------------------------------------------------------------------
%%% Client functions
%%% ---------------------------------------------------------------------------
-export([info/3, warning/3, error/3]).

%%% ---------------------------------------------------------------------------
%%% Gen_event callbacks
%%% ---------------------------------------------------------------------------
-export([start/0, stop/0, init/1, handle_event/2, terminate/2]).
-export([code_change/3, handle_call/2, handle_info/2]).

%% State record for this event handler stores displayed event count.
-define(LOG_STATE, log_state).
-record(?LOG_STATE, {info = 0,
                     warning = 0,
                     error = 0}).

%% Checks if already registered on node error_logger, and registers if
%% not.
%% @spec start() -> ok
start() ->
  ?INFO([start]),
  ErrorLogger = whereis(error_logger),
  case lists:member(?MODULE, gen_event:which_handlers(ErrorLogger)) of
    true ->
      ?INFO([{error_logger,?MODULE}, already_installed]),
      ?OK_RETURN;
    false ->
      error_logger:add_report_handler(?MODULE),
      ?INFO([{error_logger, ?MODULE}, newly_installed]),
      ?OK_RETURN
  end,
  ?OK_RETURN.

%% Removes this handler from the error_logger.
stop() ->
  error_logger:delete_report_handler(?MODULE).

%% @see gen_event
init(_Args) ->
  ?OK_RETURN(#?LOG_STATE{}).

%% Handle info report events.
%% #1
handle_event({info_report, _GroupLeader, {_EPid, ?TXM_LOG, Details}},
              #?LOG_STATE{info = Count} = State) ->
  case get_log_level() =< ?LOG_LEVEL_INFO of
    true ->
      displayInfo(Details),
      ?OK_RETURN(State#?LOG_STATE{info = Count + 1});
    false ->
      ?OK_RETURN(State)
  end;

%% #2
handle_event({warning_report, _GroupLeader, {_EPid, ?TXM_LOG, Details}},
              #?LOG_STATE{warning = Count} = State) ->
  case get_log_level() =< ?LOG_LEVEL_WARNING of
    true ->
      displayWarning(Details),
      ?OK_RETURN(State#?LOG_STATE{warning = Count + 1});
    false ->
      ?OK_RETURN(State)
  end;

%% #3
handle_event({error_report, _GroupLeader, {_EPid, ?TXM_LOG, Details}},
              #?LOG_STATE{error = Count} = State) ->
  case get_log_level() =< ?LOG_LEVEL_ERROR of
    true ->
      displayError(Details),
      ?OK_RETURN(State#?LOG_STATE{error = Count + 1});
    false ->
      ?OK_RETURN(State)
  end;

%% Ignore all other events
handle_event(_Report, State) -> ?OK_RETURN(State).

%% @see gen_event
terminate(_Args, _State) ->
  ?INFO([terminate]),
  ?OK_RETURN.

%%% ---------------------------------------------------------------------------
%%% Standard TXM error logging functions, normally invoked using the macros
%%% INFO, WARNING and ERROR defined in `txm.hrl'.
%%% ---------------------------------------------------------------------------
info(Module, Line, Report) ->
  error_logger:info_report(?TXM_LOG,
                           [{module, Module}, {line, Line},
                            {pid, self()}
                              | Report]).

warning(Module, Line, Report) ->
  error_logger:warning_report(?TXM_LOG,
                              [{module, Module}, {line, Line},
                               {pid, self()}
                                 | Report]).

error(Module, Line, Report) ->
  error_logger:error_report(?TXM_LOG,
                            [{module, Module}, {line, Line},
                             {pid, self()}
                               | Report]).

%% Formats event detail for display.
displayInfo([{module, Mod}, {line, Line}, {pid, Pid} | Report]) ->
  io:format("info: ~w:~w(~w) ~p~n", [Mod, Line, Pid, Report]).

displayWarning([{module, Mod}, {line, Line}, {pid, Pid} | Report]) ->
  io:format("warning: ~w:~w(~w) ~p~n", [Mod, Line, Pid, Report]).

displayError([{module, Mod}, {line, Line}, {pid, Pid} | Report]) ->
  io:format("error: ~w:~w(~w) ~p~n", [Mod, Line, Pid, Report]).

%%% --------------------------------------------------------------------------
%%% Utility functions
%%% --------------------------------------------------------------------------

%% @doc Returns the current logging level, defaults to info if undefined.
get_log_level() ->
  case application:get_env(?TXM_APP, ?ENV_LOG_LEVEL) of
    ?OK_RETURN(Level) -> Level;
    ?UNDEFINED -> ?LOG_LEVEL_INFO
  end.

%%% --------------------------------------------------------------------------
%%% Unimplemented behaviour functions
%%% --------------------------------------------------------------------------

code_change(_, _, _) -> throw(?REASON_NOT_IMPLEMENTED).
handle_call(_, _) -> throw(?REASON_NOT_IMPLEMENTED).
handle_info(_, _) -> throw(?REASON_NOT_IMPLEMENTED).
